package com.example.user.customviewdemo.removeitemlistview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.LinearInterpolator;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Scroller;

/**
 * Created by user on 2016/5/25.
 */
public class RemoveItemListView extends ListView {

    private static final String TAG = "RemoveItemListView";
    private VelocityTracker velocityTracker;
    private float preX;  //手指滑动时上一个x;
    private float firstX,firstY;  //手指按下时第一个x，y
    private View itemView;  //需要滑动的列表item
    private int position = INVALID_POSITION;  //要滑动列表itemView的索引位置
    private int touchStop;  //滑动的最小距离
    private static final int SNAP_VELOCITY = 600;
    private boolean isSlide;  //是否要画出itemView
    private static final int MAX_WIDTH = 500;//px
    private Scroller mScroller;
    private int deleteButtonID;//删除按钮的id

    //当itemViewe滑动的时候监听
    private OnItemScrollListener onItemScrollListener;
    interface OnItemScrollListener{
       //滑动回调函数，参数为该滑动的itemView
        void onItemScroll(int position,View view);
    }

    private OnItemDeleteListener onItemDeleteListener;
    public interface OnItemDeleteListener{
        //当点击删除按钮时的回调函数
        void OnItemDelete(int position, ListAdapter adapter);
    }



    public RemoveItemListView(Context context) {
        this(context,null);
    }
    public RemoveItemListView(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public RemoveItemListView(final Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //根据ViewConfiguration获取到手指滑动的最小距离
        touchStop = ViewConfiguration.get(context).getScaledTouchSlop();
        mScroller = new Scroller(context,new LinearInterpolator());
        mPreScroller = new Scroller(context,new LinearInterpolator());
        //添加headView
       /* TextView tv = new TextView(context);
        tv.setGravity(Gravity.CENTER);
        tv.setText("可滑动，可删除item的listview  header1");
        this.addHeaderView(tv);*/
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 该方法只是为了判断ListView的itemView按照我们的标准是否该滑动
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //先将ev关联到velocityTracker
       obtainVelocityTracker(ev);
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        int action = ev.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN:
                preX = firstX = x;
                firstY = y;
                position = pointToPosition(x,y);//得到点击item在数据源所对应的postion
                if(position != INVALID_POSITION){
                    int visiablePosition = getFirstVisiblePosition();//显示在屏幕的第一个item在数据源中的position
                    itemView = getChildAt(position - visiablePosition); //获取点击的itemView在listview中的索引index = 点击item在数据源中对应的position - 显示在屏幕的第一个item在数据源中的position

                    //如果该项item已经滑出到最大，则闭合该项
                    int scrollX = itemView.getScrollX();
                    if(scrollX == MAX_WIDTH){
                        mScroller.startScroll(scrollX,0,-scrollX,0);
                    }
                    //通知调用者该项item正在滑动
                    if(onItemScrollListener != null){
                        onItemScrollListener.onItemScroll(position,itemView);
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:

              // float xVelocity = Math.abs(velocityTracker.getXVelocity());//得到水平方向上的速率
                float dx = Math.abs(x - firstX);//相对action_dowm的x的坐标位移
                float dy = Math.abs(y - firstY);

                //这里其实只判断刚触摸时第一个滑动点，只要这个点为true，那么该次滑动事件的其他点就恒为true了
                // 不能加个else  isSlide=false，这样会产生滑动卡顿
                if(dx > touchStop && dy < touchStop){
                    isSlide = true; //表示itemView水平方向滑动
                }
                break;
            case MotionEvent.ACTION_UP:
                releaseVelocityTracker();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }


    /**
     * 该方法中将会ListView的itemView真正滑动
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(isSlide && position != INVALID_POSITION && itemView != null){
            int action = ev.getAction();
            float x = ev.getX();
            switch (action){
                case MotionEvent.ACTION_DOWN:
                    //preX = x; //这条语句不会得到执行
                    //因为在dispatchTouchEvent中当action为down事件时isSlide为false，所以这里不会执行，
                    // 所以我们的preX应当在dispathcTouchEvent中赋值，不然就为零，效果达不到预期
                    break;
                case MotionEvent.ACTION_MOVE:
                        int dx = (int) (preX - ev.getX());
                        int scrollX = dx + itemView.getScrollX();
                        //控制item的滑动范围
                        if(scrollX < 0){
                            scrollX = 0;
                        }else if(scrollX > MAX_WIDTH){
                            scrollX = MAX_WIDTH;
                        }

                        itemView.scrollTo(scrollX, 0);

                        preX = x;
                    break;
                case MotionEvent.ACTION_UP:

                    int temp = itemView.getScrollX();
                    if(temp > MAX_WIDTH/2){
                        //继续滑动至全部展开scrollX=MAX_WIDTH
                        mScroller.startScroll(temp,0,MAX_WIDTH - temp,0);
                        //为删除按钮添加点击监听
                       doDelete(position, deleteButtonID,itemView);
                    }else if(temp <= MAX_WIDTH /2){
                        //回退至scrollX=0
                        mScroller.startScroll(temp,0,-temp,0);
                    }
                   isSlide = false;
                    releaseVelocityTracker();
                    break;
            }

           return true;//一定要返回true，因为我们需要在itemView水平滑动的时候，listView就不能够垂直滑动
        }
        return super.onTouchEvent(ev);
    }

    /**
     *
     * @param position  点击的item中的数据对应adapter中数据源中的position
     * @param deleteButtonID  删除按钮的id
     * @param contentLayout   点击的item
     */
    private void doDelete(final int position ,int deleteButtonID,View contentLayout){
        if(contentLayout == null){
            return;
        }
        View view = contentLayout.findViewById(deleteButtonID);
        if(view == null){
            //如果view为null，那么表示id错误即在item中没有找到该id 抛出异常
            throw new IllegalArgumentException("not found your deleteButtonID,this id must to be contains your item layout!");
        }
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //当点击deleteButton时通知调用者
                if(onItemDeleteListener != null){
                    onItemDeleteListener.OnItemDelete(position,getAdapter());
                }
            }
        });
    }

    /**
     * 将MotionEvent 和velocityTracker关联
     * @param ev
     */
    private void obtainVelocityTracker(MotionEvent ev){
        if(velocityTracker == null){
            velocityTracker = VelocityTracker.obtain();
        }
        velocityTracker.addMovement(ev);
        velocityTracker.computeCurrentVelocity(1000);
    }

    /**
     * 释放velocityTracker
     */
    private void releaseVelocityTracker(){
        if(velocityTracker != null){
            velocityTracker.clear();
            velocityTracker.recycle();
            velocityTracker = null;
        }
    }

    @Override
    public void computeScroll() {
        if(mScroller.computeScrollOffset()){
            if(itemView != null){
                itemView.scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            }
        }
        //将所有非itemView的item回退至deleteButton影藏掉
        if(mPreScroller.computeScrollOffset()){
           preView.scrollTo(mPreScroller.getCurrX(),mPreScroller.getCurrY());
        }
        invalidate();
    }

    private View preView;
    private Scroller mPreScroller;

    /**
     * 当点击下一个itemView的时候，将第一个itemView关闭
     * @param position
     * @param itemView
     */
    public void smoothScrollItemBack(int position,View itemView){
        preView = itemView;
        int scrollX = preView.getScrollX();
        int scrollY = preView.getScrollY();
        mPreScroller.startScroll(scrollX,scrollY,-scrollX,-scrollY);
    }


    public void setOnItemScrollListener(OnItemScrollListener onItemScrollListener){
        this.onItemScrollListener = onItemScrollListener;
    }
    public void setOnItemDeleteListener(OnItemDeleteListener onItemDeleteListener){
        this.onItemDeleteListener = onItemDeleteListener;
    }

    /**
     * 设置删除按钮的id
     * @param deleteButtonID  删除按钮的id
     */
    public void setDeleteButtonID(int deleteButtonID){
        this.deleteButtonID = deleteButtonID;
    }
}
